/** Sorts an array of strings by name, A-Z by default */
export function byName(a: string, b: string, order: -1 | 1 = 1) {
	return a.localeCompare(b) * order;
}

/** Checks if two arrays of string items have equal content. */
export function arraysEqual(arr1: string[], arr2: string[]) {
	return JSON.stringify(arr1) === JSON.stringify(arr2);
}

/**
 * Compares values of objects in a sorted array using their keys.
 * Only string and number types are handled. All other data types return 0.
 * Can be used as "users.sort(compareByKey('name'))".
 * @param key used to get compared value from an object
 * @param order ASC = 1, DESC = -1, default = 1
 */
export function compareByKey<T>(key: keyof T, order: -1 | 1 = 1) {
	return (item1: T, item2: T) => {
		if (typeof item1[key] === 'string') {
			const a = item1[key] as unknown as string;
			const b = item2[key] as unknown as string;

			return a.localeCompare(b) * order;
		} else if (typeof item1[key] === 'number') {
			const a = item1[key] as unknown as number;
			const b = item2[key] as unknown as number;

			return a > b ? order : a < b ? -order : 0;
		} else {
			return 0;
		}
	};
}

/** Removes duplicate values from the array. */
export function dedupe<T>(array: T[]) {
	return [...new Set(array)];
}

/** Computes a difference between arrays by substracting array2's items from array1. */
export function difference<T>(array1: T[], array2: T[]) {
	return array1.filter((item) => !array2.includes(item));
}

/** Computes an intersection of two arrays, i.e. items they have in common. */
export function intersection<T>(array1: T[], array2: T[]) {
	return array1.filter((item) => array2.includes(item));
}

/** Item is added if it didn't exist yet or is removed if it was already in array. */
export function toggleArrayItem<T>(array: T[], item: T) {
	// prettier-ignore
	return array.includes(item)
		? array.filter(it => it !== item)
		: [...array, item];
}

/**
 * Item is added if it didn't exist yet or is removed if it was already in array.
 * Compares the item with all items in the array using provided key.
 *
 * @param array Array of objects
 * @param item Object that will be inserted or removed from array
 * @param key Property that will be used for object comparison
 */
export function toggleArrayObject<T>(array: T[], item: T, key: keyof T) {
	const hasItem = array.some((it) => it[key] === item[key]);

	// prettier-ignore
	return hasItem
		? array.filter(it => it[key] !== item[key])
		: [...array, item];
}

/** Computes a union of two arrays, preserving only unique items. */
export function union<T>(array1: T[], array2: T[]) {
	return dedupe([...array1, ...array2]);
}
